/**
 * @file
 * This file provides memorie allocations statistics and diagnostics
 */

#ifndef __EXMALLOC_H
#define __EXMALLOC_H

#ifndef __EXCEPT_H
# error "Please include except.h before exmalloc.h"
#endif /* __EXCEPT_H */

#ifndef __VECTOR_H
# error "Please include vector.h before exmalloc.h"
#endif /* __VECTOR_H */

#ifdef MEMDIAG

struct mem_samples {
    int count, size;
    int *values;
};

struct mem_diag {
    int sampleTime;
    struct vector obj_list;
    struct mem_samples samples;
    int frees;
    int reallocs;
    int mallocs;
    int peak;
    int current;
};

struct mem_obj_info {
    struct list_head list;
    void *addr;
    char file[256];
    int line;
    int size;
};

extern struct mem_diag global_mem;

# define MEM_DIAG_SETUP                                                 \
  struct mem_diag global_mem = {10, VECTOR_INIT(global_mem.obj_list), {0, 0, NULL}, 0, 0, 0, 0, 0}; \

void mem_diag_dump();

# define MEM_DIAG_SET_OPTIONS(i) do {           \
      global_mem.sampleTime = i;                \
  } while (0)

# define MEM_DIAG_DUMP mem_diag_dump()

#else /* MEMDIAG */

# define MEM_DIAG_SETUP
# define MEM_DIAG_DUMP
# define MEM_DIAG_SET_OPTIONS(i)
  
#endif /* MEMDIAG */

/**
 * exfree - custom free function to ensure NULL pointer handle
 * @addr:address to be freed
 */
#ifdef MEMDIAG
inline void exfree(void *addr, const char *file, const int line);
#else
inline void exfree(void *addr);
#endif /* MEMDIAG */

/**
 * exmalloc - custom malloc function
 * @size:size in bytes to be allocated
 */
#ifdef MEMDIAG
inline void *exmalloc(int size, const char *file, const int line);
#else
inline void *exmalloc(int size);
#endif /* MEMDIAG */

/**
 * exrealloc - custom realloc function
 * @addr:the old memory address
 * @size:new size in bytes
 */
#ifdef MEMDIAG
inline void *exrealloc(void *addr, int size, const char* file, const int line);
#else
inline void *exrealloc(void *addr, int size);
#endif /* MEMDIAG */

/** This macro is used for the real ex... implementation */
#ifndef EXMALLOC_IMPL

#ifdef malloc
# undef malloc
#endif /* malloc */

#ifdef realloc
# undef realloc
#endif /* realloc */

#ifdef free
# undef free
#endif /* free */

#ifdef MEMDIAG
# define malloc(s)     exmalloc(s, __FILE__, __LINE__)
# define realloc(a, s) exrealloc(a, s, __FILE__, __LINE__)
# define free(a)       exfree(a, __FILE__, __LINE__)
#else /* MEMDIAG */
# define malloc(s)     exmalloc(s)
# define realloc(a, s) exrealloc(a, s)
# define free(a)       exfree(a)
#endif /* MEMDIAG */

#endif /* EXMALLOC_IMPL */

#endif /* __EXMALLOC_H */
